#include "threadCache.h"

namespace cache
{
    CThreadVariable::CThreadVariable()
    {
        m_pNode = new SNode[HEAD_SIZE];
        assert(m_pNode != NULL);
        pthread_mutex_init(&m_mutex, 0);
        m_iStoryTimes = 0;
    }

    CThreadVariable::~CThreadVariable()
    {
        pthread_mutex_destroy( &m_mutex);
        SNode*    pNode = NULL;
        SNode*    pNext = NULL;
        for(int i = 0; i < HEAD_SIZE; ++i){
            pNode = m_pNode[i].m_pNext;
            while( pNode){
                pNext = pNode->m_pNext;
                delete pNode;
                pNode = pNext;
            }
        }
        delete[] m_pNode;
    }

    SNode* CThreadVariable::get_var()
    {
        pthread_t nTid = pthread_self();
        int index = ((int)nTid) % HEAD_SIZE;
        index = index < 0 ? -index : index;
        SNode *pHead = &m_pNode[index];
        // Hash detected new space
        if (pHead->m_nTid == 0){
            pthread_mutex_lock(&m_mutex);
            if (pHead->m_nTid == 0) pHead->m_nTid = nTid;
            pthread_mutex_unlock(&m_mutex);
        }
        // Hash detects old space
        if (pHead->m_nTid == nTid) return pHead;
        // Hash detection collides
        pthread_mutex_lock(&m_mutex);        
        SNode *pNode = pHead->m_pNext;
        pthread_mutex_unlock(&m_mutex); 
        while (pNode){
            if (pNode->m_nTid == nTid) return pNode;
            pNode = pNode->m_pNext;
        }
        return insert(pHead);
    }

    SNode* CThreadVariable::get_var(pthread_t nTid)
    {
        int index = ((int)nTid) % HEAD_SIZE;
        index = index < 0 ? -index : index;
        SNode *pHead = &m_pNode[index];
        // Hash detected new space
        if (pHead->m_nTid == 0){
            pthread_mutex_lock(&m_mutex);
            if (pHead->m_nTid == 0) pHead->m_nTid = nTid;
            pthread_mutex_unlock(&m_mutex);
        }
        // Hash detects old space
        if (pHead->m_nTid == nTid) return pHead;
        // Hash detection collides
        pthread_mutex_lock(&m_mutex);        
        SNode *pNode = pHead->m_pNext;
        pthread_mutex_unlock(&m_mutex); 
        while (pNode){
            if (pNode->m_nTid == nTid) return pNode;
            pNode = pNode->m_pNext;
        }
        return insert(pHead);
    }

    SNode* CThreadVariable::insert(SNode *pHead)
    {
        SNode *pNode = new SNode;
        pNode->m_nTid = pthread_self();
        pNode->m_pNext = pHead->m_pNext;
        pthread_mutex_lock(&m_mutex);
        pHead->m_pNext = pNode;             
        pthread_mutex_unlock(&m_mutex);
        return pNode;
    }
}
